package icegps.com.pingdj.map.utils;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

import icegps.com.pingdj.map.MapManager;
import icegps.com.pingdj.map.MapView;
import icegps.com.pingdj.map.bean.MapStatus;
import icegps.com.pingdj.map.bean.MapText;
import icegps.com.pingdj.map.bean.XYCAD;
import icegps.com.pingdj.map.count.ScreenCount;
import icegps.com.pingdj.map.lrucache.ArrayDataLruCahe;
import icegps.com.pingdj.map.lrucache.BitmapLruCache;
import icegps.com.pingdj.map.thread.MapRunnable;
import icegps.com.pingdj.map.thread.ThreadPool;

import static java.lang.Float.parseFloat;


/**
 * Created by 111 on 2018/3/29.
 */
public class TileUtils {
    public static int tileLength = 200;
    public static long loadToken;
    public static long saveToken;
    public BitmapLruCache bitmapLruCache;
    public ArrayDataLruCahe arrayDataLruCahe;
    public Set<String> bitmapNames;
    private float oldSumTx;
    private float oldSumTy;
    public HashMap<String,MapText> hashMap;

    public TileUtils(long loadToken, long saveToken) {
        TileUtils.loadToken = loadToken;
        TileUtils.saveToken = saveToken;
        bitmapNames = new TreeSet<>();
        hashMap=new HashMap<>();
        bitmapLruCache = new BitmapLruCache(loadToken);
        arrayDataLruCahe = new ArrayDataLruCahe(loadToken);
    }


    public double getDrawTextX(double x,int length) {
        double drawTextX = x;
        drawTextX = Math.floor(drawTextX / (length));
        drawTextX = drawTextX * length;
        return drawTextX;
    }

    public double getDrawTextY(double y,int length) {
        double drawTextY = y;
        drawTextY = Math.floor(drawTextY / (length));
        drawTextY = drawTextY * length;
        return drawTextY;
    }

    /**
     * 通过y计算当前方块的top
     *
     * @param y
     * @return
     */
    public double getTop(double y) {
        double bitmapY = y;
        bitmapY = Math.floor(bitmapY / (tileLength));
        bitmapY = bitmapY * tileLength;
        return bitmapY;
    }

    /**
     * 根据X计算当前方块的left
     *
     * @param x
     * @return
     */
    public double getLeft(double x) {
        double bitmapX = x;
        bitmapX = Math.floor(bitmapX / (tileLength));
        bitmapX = bitmapX * tileLength;
        return bitmapX;
    }

    /**
     * 根据Y计算当前所处方块的Y
     *
     * @param y
     * @return
     */
    public int getY(float y) {
        float remainder = y % tileLength;
        if (remainder >= 0) {
            y = remainder;
        } else {
            y = tileLength - Math.abs(remainder);
        }
        return (int) Math.floor(y);
    }

    /**
     * 根据X计算当前所处方块的X
     *
     * @param x
     * @return
     */
    public int getX(float x) {
        float remainder = x % tileLength;
        if (remainder >= 0) {
            x = remainder;
        } else {
            x = tileLength - Math.abs(remainder);
        }
        return (int) Math.floor(x);
    }

    /**
     * 查找此坐标是否已经存在,若存在则返回高差
     *
     * @param x
     * @param y
     * @return
     */
    public Float locationExists(int x, int y) {
        int bitmapLeft = (int) getLeft(x);
        int bitmapTop = (int) getTop(y);
        int pixelX = getX((float) x);
        int pixelY = getY((float) y);
        String name = new String(bitmapLeft + "," + bitmapTop);
        Float[][] floats = arrayDataLruCahe.get(name);
        if (floats == null) {
            return null;
        } else {
            return floats[pixelX][pixelY];
        }
    }

    /**
     * 1,处理所绘制的图片
     * 2,处理原始数据的数组
     *
     * @param xycad
     * @param mapStatus
     */
    public void setTileData(XYCAD xycad, MapStatus mapStatus) {
        int bitmapLeft = (int) getLeft(xycad.getX());
        int bitmapTop = (int) getTop(xycad.getY());
        int pixelX = getX((float) xycad.getX());
        int pixelY = getY((float) xycad.getY());
        String name = new String(bitmapLeft + "," + bitmapTop);
        setBitmapTile(mapStatus, xycad, pixelX, pixelY, name);
        setArrayDataTile(xycad, pixelX, pixelY, name);
        isLoadBitmap(mapStatus);
    }

    /**
     * 处理原始数据的数组
     *
     * @param xycad
     * @param pixelX
     * @param pixelY
     * @param name
     */
    private void setArrayDataTile(XYCAD xycad, int pixelX, int pixelY, String name) {
        Float[][] floats = arrayDataLruCahe.get(name);

        if (floats == null) {
            floats = new Float[tileLength][tileLength];
        }
        if (floats != null) {
            floats[pixelX][pixelY] = xycad.getDifference();
            arrayDataLruCahe.add(name, floats);
        }
    }

    /**
     * 处理所绘制的图片
     *
     * @param mapStatus
     * @param xycad
     * @param pixelX
     * @param pixelY
     * @param name
     */
    private void setBitmapTile(MapStatus mapStatus, XYCAD xycad, int pixelX, int pixelY, String name) {
        Bitmap bitmap = bitmapLruCache.get(name);
        if (bitmap == null) {
            bitmap = Bitmap.createBitmap(getEmptyBitmap(), 0, 0, tileLength, tileLength);
        }
        if (bitmap != null) {
            bitmap.setPixel(pixelX, pixelY, xycad.getColor());
            bitmapLruCache.add(name, bitmap);
            mapStatus.getBitmaps().put(name, bitmap);
        }
    }

    /**
     * 移动超过一个方块的长度就重新判断并加载图片
     *
     * @param mapStatus
     */
    private void isLoadBitmap(MapStatus mapStatus) {
        float sumTx = mapStatus.getSumTx();
        float sumTy = mapStatus.getSumTy();
        if (Math.abs(sumTx - oldSumTx) > tileLength * mapStatus.getMultiple() * 2 || Math.abs(sumTy - oldSumTy) > tileLength * mapStatus.getMultiple()) {
            oldSumTx = sumTx;
            oldSumTy = sumTy;
            loadBitmapTile(mapStatus);
        }
    }

    /**
     * 加载图片
     *
     * @param mapStatus
     */
    public void loadTile(MapStatus mapStatus) {
        ThreadPool.getInstance().executeFixed(new MapRunnable() {
            @Override
            public void run() {
                super.run();
                loadBitmapTile(mapStatus);
            }

            @Override
            protected String threadName() {
                return "loacdTile";
            }
        });

    }

    /**
     * 加载图片
     *
     * @param mapStatus
     */
    private void loadBitmapTile(MapStatus mapStatus) {
        TreeMap<String, Bitmap> bitmaps = mapStatus.getBitmaps();
        bitmapNames.addAll(bitmapLruCache.getKeys());
        File[] files = FileUtils.getDir(FileUtils.BITMAP_DIR, loadToken).listFiles();
        if (files == null) return;
        for (File file : files) {
            bitmapNames.add(file.getName());
        }
        float screenCxByTx = ScreenCount.getScreenCxByTx(mapStatus);

        float screenCyByTy = ScreenCount.getScreenCyByTy(mapStatus);

        float screenLeft = screenCxByTx - MapManager.windowWidth;

        float screenTop = screenCyByTy - MapManager.windowHeight;

        float screenRight = screenCxByTx + MapManager.windowWidth;

        float screenBottom = screenCyByTy + MapManager.windowHeight;

        try {
            float tileLength = TileUtils.tileLength * mapStatus.getMultiple();
            if (files == null) return;
            for (String name : bitmapNames) {
                String[] split = name.split(",");
                float tileTop = parseFloat(split[1]) * mapStatus.getMultiple();
                float tileLeft = parseFloat(split[0]) * mapStatus.getMultiple();
                float tileBottom = tileTop + tileLength;
                float tileRight = tileLeft + tileLength;
                //判断方块是否在屏幕内
                if (tileLeft < screenRight &&
                        tileRight > screenLeft &&
                        tileTop < screenBottom &&
                        tileBottom > screenTop
                        ) {
                    Bitmap bitmap = bitmapLruCache.get(name);
                    if (bitmap == null) {
                        bitmap = getBitmap(name, loadToken);
                    }
                    if (bitmap != null && name != null) {
                        bitmapLruCache.add(name, bitmap);
                        bitmaps.put(name, bitmap);
                    }
                } else {
                    bitmaps.remove(name);
                }
            }
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
    }

    /**
     * 加载原始数据数组方块
     *
     * @param arrayDataName
     * @param token
     * @return
     */
    private static Float[][] getArrayData(String arrayDataName, long token) {
        try {
            FileInputStream fis = new FileInputStream(FileUtils.getFile(FileUtils.ARRAY_DATA_DIR, token, arrayDataName));
            ObjectInputStream objectInputStream = new ObjectInputStream(fis);
            Float[][] f = (Float[][]) objectInputStream.readObject();
            if (f != null) {
                return f;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param bitmapName 图片名称
     * @param token      文件夹名称
     * @return
     */
    private static Bitmap getBitmap(String bitmapName, long token) {
        File file = null;
        try {
            file = FileUtils.getFile(FileUtils.BITMAP_DIR, token, bitmapName);
            Bitmap bitmap = BitmapFactory.decodeFile(file.getPath()).copy(Bitmap.Config.ARGB_8888, true);
            return bitmap;
        } catch (Exception e) {
            file.delete();
            return null;
        }
    }

    /**
     * 保存原始数据以及图片数据
     */
    public void saveAllTile() {
        for (String key : bitmapLruCache.getKeys()) {
            saveBitmap(key, bitmapLruCache.get(key), saveToken);
            saveArrayData(key, arrayDataLruCahe.get(key), saveToken);
        }

    }

    /**
     * 保存单个原始数据方块
     *
     * @param arrayDataName
     * @param arrayData
     * @param token
     */
    public static void saveArrayData(String arrayDataName, Float[][] arrayData, long token) {
        File file = null;
        file = FileUtils.getFile(FileUtils.ARRAY_DATA_DIR, token, arrayDataName);
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        try {
            ObjectOutputStream oout = new ObjectOutputStream(bout);
            oout.writeObject(arrayData);
            byte[] b = bout.toByteArray();
            FileOutputStream out = new FileOutputStream(file);
            out.write(b);
            out.flush();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 保存单张图片
     *
     * @param bitmapName
     * @param bitmap
     * @param token
     * @return
     */
    public static boolean saveBitmap(String bitmapName, Bitmap bitmap, long token) {
        BufferedOutputStream out = null;
        File file = null;
        try {
            file = FileUtils.getFile(FileUtils.BITMAP_DIR, token, bitmapName);
            out = new BufferedOutputStream(new FileOutputStream(file));
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
            out.flush();
            out.close();
            return true;
        } catch (FileNotFoundException e) {
            file.delete();
            return false;
        } catch (IOException e) {
            file.delete();
            return false;
        }
    }

    /**
     * 初始化一张透明图片
     *
     * @return
     */
    private static Bitmap getEmptyBitmap() {
        Bitmap bitmap = Bitmap.createBitmap(tileLength, tileLength, Bitmap.Config.ARGB_4444);
        Canvas canvas = new Canvas(bitmap);
        canvas.drawColor(Color.parseColor("#00000000"));
        return bitmap;
    }

    /**
     * 删除方块数据(图片+原始数据)
     *
     * @param token
     * @return
     */
    public static boolean deleteTile(long token) {
        File dir = FileUtils.getDir(FileUtils.BITMAP_DIR, token);
        deleteTile(dir);
        if (dir.listFiles() == null || dir.listFiles().length == 0) {
            return true;
        }
        return false;
    }

    /**
     * 递归删除
     *
     * @param dir
     */
    private static void deleteTile(File dir) {
        if (dir.isDirectory()) {
            File[] files = dir.listFiles();
            for (File file : files) {
                deleteTile(file);
                file.delete();
            }
        } else if (dir.isFile()) {
            dir.delete();
        }
    }
}
